const { Op } = require('sequelize')
const { getAddAndRemoveIdList } = require('../../../shared/repository/helper')
const SequelizeRepository = require('../../../shared/repository/SequelizeRepository')
const R = require('ramda')
const MenuType = require('../../../domain/menu/MenuType')
class UserRepository extends SequelizeRepository {
  constructor({ database, userCoverter }) {
    super({
      coverter: userCoverter,
      model: database.models.User,
    })
    this.models = database.models
  }
  async findByUsername(username) {
    return await this.findOne({ where: { username } })
  }
  async findByEmail(email) {
    return await this.findOne({ where: { email } })
  }
  async findByPhone(phone) {
    return await this.findOne({ where: { phone } })
  }
  async findByAccount(account) {
    return await this.findOne({
      where: { [Op.or]: { username: account, email: account, phone: account } },
    })
  }
  toRole(id) {
    const { Role } = this.models
    const role = new Role()
    role.id = id
    return role
  }
  toRoleList(roleIdList = []) {
    return roleIdList.map((id) => this.toRole(id))
  }
  async createAndSetRoleList(entity, { transaction, currentUser }) {
    const { roleList, ...data } = entity
    const user = await this.model.create(
      {
        ...data,
        createdBy: this.getUsername(currentUser),
      },
      { transaction }
    )
    if (roleList && roleList.length > 0) {
      await user.setRoleList(
        roleList.map((item) => this.toRole(item)),
        {
          transaction,
        }
      )
    }

    return this.coverter.toEntity(user)
  }

  async updateAndRoleList(entity, roleIdList, { transaction, currentUser }) {
    const { id, email, phone } = this.coverter.toDatabase(entity)
    const user = await this.model.findByPk(entity.id, {
      include: ['roleList'],
    })
    const { deleteIds, addIds } = getAddAndRemoveIdList(
      R.map(R.prop('id'), user.roleList),
      roleIdList
    )
    await user.removeRoleList(this.toRoleList(deleteIds), { transaction })
    await user.addRoleList(this.toRoleList(addIds), { transaction })
    await user.update(
      {
        email,
        phone,
        updatedBy: this.getUsername(currentUser),
      },
      { where: { id }, transaction }
    )
  }

  async findUserSystemMenu(userId, systemId) {
    const { Role, Menu } = this.models
    const user = await this.model.findByPk(userId, {
      include: [
        {
          model: Role,
          as: 'roleList',
          include: [
            {
              model: Menu,
              as: 'menuList',
            },
          ],
        },
      ],
    })
    const menuList = R.compose(
      R.filter(R.compose(R.equals(systemId), R.prop('systemId'))),
      R.flatten,
      R.map(R.prop('menuList')),
      R.prop('roleList')
    )(user.toJSON())
    return menuList
  }
}

module.exports = UserRepository
